package com.jintian.smart.kernel.common.expr;

import com.jintian.smart.kernel.common.expr.datameta.Constant;
import com.jintian.smart.kernel.common.expr.datameta.Variable;
import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.expr.IllegalExpressionException;
import org.flowable.cmmn.model.VariableAggregationDefinition;

import java.util.Collection;
import java.util.List;

/**
 * IK-Expression 表达式解析器（主入口程序） ExpressionEvaluator 是多线程安全的
 */
public class ExpressionEvaluator {

    /**
     * 验证表达式
     *
     * @param expression
     * @return
     */
    public static String compile(String expression) {
        return compile(expression, null);
    }

    /**
     * 验证表达式
     *
     * @param expression
     * @param variables
     * @return
     * @throws IllegalExpressionException
     */
    public static String compile(String expression, Collection<VariableAggregationDefinition.Variable> variables) {
        if (expression == null) {
            throw new IllegalExpressionException("表达式为空");
        }
        // 解析表达式词元
        List<ExpressionToken> expTokens = ExpressionExecutor.analyze(expression);
        // 转化RPN，并验证
        expTokens = ExpressionExecutor.compile(expTokens);
        // 以字符串形式输出RPN
        return ExpressionExecutor.tokensToString(expTokens);
    }

    /**
     * 执行无变量表达式
     *
     * @param expression
     * @return
     */
    public static Object evaluate(String expression) {
        return evaluate(expression, null);
    }

    /**
     * 计算表达式
     *
     * @param expression
     * @param variables
     * @return
     */
    public static Object evaluate(String expression, Collection<Variable> variables) {
        if (StringUtil.isEmpty(expression)) {
            return null;
        }
        // 解析表达式词元
        List<ExpressionToken> expTokens = ExpressionExecutor.analyze(expression);
        // 获取上下文的变量，设置到脚本执行器中
        if (variables != null && variables.size() > 0) {
            for (Variable var : variables) {
                // 添加变来到脚本变量容器
                VariableContainer.addVariable(var);
            }
        }
        // 转化RPN，并验证
        expTokens = ExpressionExecutor.compile(expTokens);
        return ExpressionEvaluator.evaluate(expTokens, null, true);
    }

    /**
     * 计算词元
     *
     * @param expTokens
     * @return
     */
    public static Object evaluate(List<ExpressionToken> expTokens) {
        return evaluate(expTokens, null, false);
    }

    /**
     * 计算词元
     *
     * @param expTokens
     * @param variables
     * @return
     */
    public static Object evaluate(List<ExpressionToken> expTokens, Collection<Variable> variables, boolean compiled) {
        try {
            // 获取上下文的变量，设置到脚本执行器中
            if (variables != null && variables.size() > 0) {
                for (Variable var : variables) {
                    // 添加变来到脚本变量容器
                    VariableContainer.addVariable(var);
                }
            }
            // 转化RPN，并验证
            if (!compiled)
                expTokens = ExpressionExecutor.compile(expTokens);
            // 执行RPN
            Constant constant = ExpressionExecutor.execute(expTokens);
            return constant.toJavaObject();

        } finally {
            // 释放脚本变量容器
            VariableContainer.removeVariableMap();
        }
    }

    /**
     * 逐个添加表达式上下文变量
     *
     * @param variable
     */
    public static void addVarible(Variable variable) {
        // 添加变来到脚本变量容器
        VariableContainer.addVariable(variable);
    }

    /**
     * 批量添加表达式上下文变量
     *
     * @param variables
     */
    public static void addVaribles(Collection<Variable> variables) {
        // 获取上下文的变量，设置到脚本执行器中
        if (variables != null && variables.size() > 0) {
            for (Variable var : variables) {
                // 添加变来到脚本变量容器
                VariableContainer.addVariable(var);
            }
        }
    }
}
